package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.context.OrderHandlerInterceptorContext;
import com.atguigu.tingshu.order.context.OrderTradeStrategyContext;
import com.atguigu.tingshu.order.enumeration.OrderStatusEnum;
import com.atguigu.tingshu.order.enumeration.PayWayEnum;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderDerateService;
import com.atguigu.tingshu.order.service.OrderDetailService;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.order.strategy.OrderTradeStrategy;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private KafkaService kafkaService;

    @Autowired
    private OrderDetailMapper orderDetailMapper;


    /**
     * 这个trade方法是三种购买方式的统一如果，由于购买方式不同，因此在构建结算页所需要数据的时候的逻辑代码肯定相同
     * 因此这里需要进行判断，判断付款项目的类型，根据类型不同执行不同的代码逻辑
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo) {

        String itemType = tradeVo.getItemType();

        OrderTradeStrategy orderTradeStrategy = OrderTradeStrategyContext.getOrderTradeStrategy(itemType);
        OrderInfoVo orderInfoVo = orderTradeStrategy.trade(tradeVo);

        return null;
    }

    @Override
    public String submitOrder(OrderInfoVo orderInfoVo) {
        OrderInfoVo infoVo = OrderHandlerInterceptorContext.entry(orderInfoVo);
        return infoVo.getTradeNo();
    }


    /**
     * 并发访问的问题：更改订单的状态存在两个业务
     * 1、订单超时未支付取消订单
     * 2、支付成功以后更改订单的状态   ----> 就会把订单的状态改为已支付
     *
     * 在判断完毕以后，更改支付状态为已取消之前，用户支付了，那么此时就会把订单的状态先被改成已支付，更改完毕以后，在执行
     * orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);               // 把订单的状态改为已取消
     * orderInfoMapper.updateById(orderInfo) ;
     * 订单的状态就变成已取消。
     *
     * 存在问题：用户支付成功了，但是订单的状态是已取消。
     *
     * 问题解决方案：加锁
     *
     * 悲观锁: 就是站在悲观角度去看待问题，认为当前线程对数据操作的时候，其他的线程也会对数据进行操作，因此当前线程对数据操作之前直接加锁。弊端：程序效率太低了。
     * 乐观锁: 就是站在乐观角度去看待问题，认为当前线程对数据操作的时候,其他的线程也会对数据进行操作,  因此在当前线程对数据操作之前不会进行加锁，当针对对数据要进行修改的时候
     *        判断一下，判断当前线程对数据操作的时候有没有其他的线程对数据进行了修改，如果没有就执行修改操作，如果有就执行修改操作失败。
     * 举例：半杯水
     */
    @Override
    public void canalOrder(String orderNo) {


        // 根据订单编号从数据库中查询订单数据
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
        lambdaQueryWrapper.eq(OrderInfo::getOrderNo , orderNo) ;
        OrderInfo orderInfo = orderInfoMapper.selectOne(lambdaQueryWrapper);

        // 判断订单的状态
        if(SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())) {     // 表示未支付
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);               // 把订单的状态改为已取消
            lambdaQueryWrapper.eq(OrderInfo::getOrderStatus , SystemConstant.ORDER_STATUS_UNPAID) ;
            orderInfoMapper.update(orderInfo , lambdaQueryWrapper) ;
            // update order_info set order_status = '0903' where id = ?
            // update order_info set order_status = '0903' where order_no = ? and order_status = '0901'     // 乐观锁的思想
            log.info("订单编号为{}订单的状态被更改为了已取消..." , orderNo );
        }

    }

    @Override
    public void orderPaySuccess(String orderNo) {


        // 修改订单的状态，为已支付
        updateOrderStatus(orderNo , SystemConstant.ORDER_STATUS_PAID) ;

        // 向Kafka中发送保存购买信息的消息
        OrderInfo orderInfo = getOrderInfo(orderNo);
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo() ;
        userPaidRecordVo.setOrderNo(orderNo);
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());
        List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(orderDetail -> orderDetail.getItemId()).collect(Collectors.toList());
        userPaidRecordVo.setItemIdList(itemIdList);

        // 发送消息
        kafkaService.sendMsg(KafkaConstant.QUEUE_USER_PAY_RECORD , JSON.toJSONString(userPaidRecordVo));

    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {

        // 查询订单的基本数据
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
        lambdaQueryWrapper.eq(OrderInfo::getOrderNo , orderNo) ;
        OrderInfo orderInfo = orderInfoMapper.selectOne(lambdaQueryWrapper);

        // 根据订单的id查询订单明细数据
        LambdaQueryWrapper<OrderDetail> detailLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
        detailLambdaQueryWrapper.eq(OrderDetail::getOrderId , orderInfo.getId()) ;
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(detailLambdaQueryWrapper);
        orderInfo.setOrderDetailList(orderDetailList) ;

        // 构建payWayName字段的值和orderStatusName字段的值
        String payWay = orderInfo.getPayWay();
        String payWayName = PayWayEnum.getPayWayName(payWay);
        orderInfo.setPayWayName(payWayName);

        String orderStatusName = OrderStatusEnum.getOrderStatusName(orderInfo.getOrderStatus());
        orderInfo.setOrderStatusName(orderStatusName);

        return orderInfo ;
    }

    @Override
    public IPage<OrderInfo> findUserPage(Integer pageNo, Integer pageSize) {

        // 获取当前登录用户的id
        Long userId = AuthContextHolder.getUserId();
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
        lambdaQueryWrapper.eq(OrderInfo::getUserId , userId) ;
        IPage<OrderInfo> page = new Page<>(pageNo , pageSize) ;
        this.page(page , lambdaQueryWrapper) ;

        page.getRecords().forEach(orderInfo -> {
            orderInfo.setPayWayName(PayWayEnum.getPayWayName(orderInfo.getPayWay()));
            orderInfo.setOrderStatusName(OrderStatusEnum.getOrderStatusName(orderInfo.getOrderStatus()));
            LambdaQueryWrapper<OrderDetail> detailLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
            detailLambdaQueryWrapper.eq(OrderDetail::getOrderId , orderInfo.getId()) ;
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(detailLambdaQueryWrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        });

        return page;
    }

    private void updateOrderStatus(String orderNo, String orderStatus) {
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
        lambdaQueryWrapper.eq(OrderInfo::getOrderNo , orderNo) ;
        OrderInfo orderInfo = orderInfoMapper.selectOne(lambdaQueryWrapper);
        orderInfo.setOrderStatus(orderStatus);
        orderInfoMapper.updateById(orderInfo) ;
    }
}
